<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 5.2.0">
  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">


<link rel="stylesheet" href="/lib/font-awesome/css/all.min.css">

<script id="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"llmysnow.top","root":"/","scheme":"Gemini","version":"7.8.0","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":true,"show_result":true,"style":null},"back2top":{"enable":true,"sidebar":false,"scrollpercent":true},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":true,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":true,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},"path":"search.xml"};
  </script>

  <meta name="description" content="webpack的优化配置；webpack的依赖优化；基于webpack的代码拆分&#x2F;资源压缩&#x2F;资源持久化缓存；React按需加载实现方式">
<meta property="og:type" content="article">
<meta property="og:title" content="优化5.构建优化">
<meta property="og:url" content="http://llmysnow.top/posts/e8da84b8/index.html">
<meta property="og:site_name" content="奇幻的梦之旅">
<meta property="og:description" content="webpack的优化配置；webpack的依赖优化；基于webpack的代码拆分&#x2F;资源压缩&#x2F;资源持久化缓存；React按需加载实现方式">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://gitee.com/lilyn/pic/raw/master/jslearn-img/202203071749797.png">
<meta property="og:image" content="https://gitee.com/lilyn/pic/raw/master/jslearn-img/202203091013592.png">
<meta property="og:image" content="https://gitee.com/lilyn/pic/raw/master/jslearn-img/202203101448357.png">
<meta property="og:image" content="https://gitee.com/lilyn/pic/raw/master/jslearn-img/202203101457701.png">
<meta property="og:image" content="https://gitee.com/lilyn/pic/raw/master/jslearn-img/202203101459723.png">
<meta property="article:published_time" content="2022-04-23T11:27:04.407Z">
<meta property="article:modified_time" content="2022-04-23T11:27:47.131Z">
<meta property="article:author" content="LiLyn">
<meta property="article:tag" content="性能优化">
<meta property="article:tag" content="webpack 优化配置">
<meta property="article:tag" content="webpack 依赖优化">
<meta property="article:tag" content="webpack 细节优化">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://gitee.com/lilyn/pic/raw/master/jslearn-img/202203071749797.png">

<link rel="canonical" href="http://llmysnow.top/posts/e8da84b8/">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : false,
    isPost : true,
    lang   : 'zh-CN'
  };
</script>

  <title>优化5.构建优化 | 奇幻的梦之旅</title>
  






  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

<link rel="alternate" href="/atom.xml" title="奇幻的梦之旅" type="application/atom+xml">
</head>
<!--即时预加载技术，在用户点击之前预先加载页面-->
<script src="https://cdn.jsdelivr.net/gh/TRHX/CDN-for-itrhx.com@2.0.2/js/instantclick-1.2.2.js" type="module"></script>
<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>
	  <!--<a target="_blank" rel="noopener" href="https://github.com/llwodexue" class="github-corner" aria-label="View source on GitHub"><svg width="80" height="80" viewBox="0 0 250 250" style="fill:#151513; color:#fff; position: absolute; top: 0; border: 0; right: 0;" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a><style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}</style>-->
    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <h1 class="site-title">奇幻的梦之旅</h1>
      <span class="logo-line-after"><i></i></span>
    </a>
      <p class="site-subtitle" itemprop="description">http://llmysnow.top/</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
        <i class="fa fa-search fa-fw fa-lg"></i>
    </div>
  </div>
</div>




<nav class="site-nav">
  <ul id="menu" class="main-menu menu">
        <li class="menu-item menu-item-home">

    <a href="/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a>

  </li>
        <li class="menu-item menu-item-tags">

    <a href="/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档</a>

  </li>
      <li class="menu-item menu-item-search">
        <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
        </a>
      </li>
  </ul>
</nav>



  <div class="search-pop-overlay">
    <div class="popup search-popup">
        <div class="search-header">
  <span class="search-icon">
    <i class="fa fa-search"></i>
  </span>
  <div class="search-input-container">
    <input autocomplete="off" autocapitalize="off"
           placeholder="搜索..." spellcheck="false"
           type="search" class="search-input">
  </div>
  <span class="popup-btn-close">
    <i class="fa fa-times-circle"></i>
  </span>
</div>
<div id="search-result">
  <div id="no-result">
    <i class="fa fa-spinner fa-pulse fa-5x fa-fw"></i>
  </div>
</div>

    </div>
  </div>

</div>
    </header>

    
  <div class="back-to-top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content post posts-expand">
            

    
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="http://llmysnow.top/posts/e8da84b8/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/logo.jpg">
      <meta itemprop="name" content="LiLyn">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="奇幻的梦之旅">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          优化5.构建优化
        </h1>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2022-04-23 19:27:04" itemprop="dateCreated datePublished" datetime="2022-04-23T19:27:04+08:00">2022-04-23</time>
            </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96/" itemprop="url" rel="index"><span itemprop="name">性能优化</span></a>
                </span>
            </span>

          <br>
            <span class="post-meta-item" title="本文字数">
              <span class="post-meta-item-icon">
                <i class="far fa-file-word"></i>
              </span>
                <span class="post-meta-item-text">本文字数：</span>
              <span>9.2k</span>
            </span>
            <span class="post-meta-item" title="阅读时长">
              <span class="post-meta-item-icon">
                <i class="far fa-clock"></i>
              </span>
                <span class="post-meta-item-text">阅读时长 &asymp;</span>
              <span>8 分钟</span>
            </span>
            <div class="post-description">webpack的优化配置；webpack的依赖优化；基于webpack的代码拆分/资源压缩/资源持久化缓存；React按需加载实现方式</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
        <h2 id="webpack-优化配置"><a href="#webpack-优化配置" class="headerlink" title="webpack 优化配置"></a>webpack 优化配置</h2><p>webpack4 引入了 mode 模式，可以配置开发和生产模式，就可以使用一些已经默认好的插件帮我们达到想做的效果</p>
<p><img data-src="https://gitee.com/lilyn/pic/raw/master/jslearn-img/202203071749797.png"></p>
<h3 id="Tree-shaking"><a href="#Tree-shaking" class="headerlink" title="Tree-shaking"></a>Tree-shaking</h3><ul>
<li><p>上下文未用到的代码（dead code）</p>
</li>
<li><p>给予 ES6 import export</p>
<p>Tree-shaking 基础：无论是自己还是第三方，必须是模块化的，要基于 ES6 import export 导入导出的形式才可以，生产模式会默认启动 Tree-shaking，主要依赖于 <code>TerserPlugin</code> 插件</p>
<p>Tree-shaking 原理：从 index.js 开始，去看引用了哪些东西，进一步分析所有引入的包或模块里又引用了哪些模块或其他一些包，最后会把需要的东西都留下</p>
</li>
<li><p><code>package.json</code> 中配置 <code>sideEffects</code></p>
<p>因为它的实现是基于一定的规则，不过在 JS 里，可能会涉及到修改全局作用域（window 对象），如果把这个 shake 掉，代码就会出现问题，这时就需要使用 <code>sideEffects</code> 来告诉 webpack 哪些文件不需要 shake</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">&quot;sideEffects&quot;</span>: [</span><br><span class="line">  <span class="string">&quot;*.css&quot;</span></span><br><span class="line">]</span><br></pre></td></tr></table></figure>
</li>
<li><p>注意 Babel 默认配置的影响</p>
<p><code>presets</code> 就是把常用的 babel 插件做了一个集合。它有个问题：在转码时会把 ES6 模块化的语法转换成其他语法，我们希望保留 ES6 模块化语法，所以要加上 <code>modules: false</code>，这样 Tree-shaking 才能起到作用</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  presets: [</span><br><span class="line">    [</span><br><span class="line">      <span class="string">&#x27;@babel/preset-env&#x27;</span>,</span><br><span class="line">      &#123;</span><br><span class="line">        modules: <span class="literal">false</span>,</span><br><span class="line">        targets: &#123;</span><br><span class="line">          browsers: [<span class="string">&#x27;&gt;0.25%&#x27;</span>],</span><br><span class="line">        &#125;,</span><br><span class="line">        useBuiltIns: <span class="string">&#x27;usage&#x27;</span>,</span><br><span class="line">        bugfixes: <span class="literal">true</span>,</span><br><span class="line">      &#125;,</span><br><span class="line">    ],</span><br><span class="line">    <span class="string">&#x27;@babel/preset-react&#x27;</span>,</span><br><span class="line">  ],</span><br><span class="line">  plugins: [<span class="string">&#x27;@babel/plugin-proposal-class-properties&#x27;</span>, <span class="string">&#x27;@babel/plugin-transform-runtime&#x27;</span>],</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

</li>
</ul>
<h3 id="JS-压缩"><a href="#JS-压缩" class="headerlink" title="JS 压缩"></a>JS 压缩</h3><blockquote>
<p><a target="_blank" rel="noopener" href="https://juejin.cn/post/6844904094281236487#refetch">再来一打Webpack面试题</a></p>
</blockquote>
<ul>
<li><p><code>uglifyjs-webpack-plugin</code>：不支持 ES6 压缩 (Webpack4 以前)</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> UglifyJsPlugin = <span class="built_in">require</span>(<span class="string">&#x27;uglifyjs-webpack-plugin&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  optimization: &#123;</span><br><span class="line">    minimizer: [<span class="keyword">new</span> UglifyJsPlugin()],</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li><p><code>terser-webpack-plugin</code>：支持压缩 ES6 (Webpack4)</p>
<p>terser 无论从销量还是效果上都比 uglifyjs 好，所以 terser 后面座位生产模式下默认的压缩插件</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> TerserPlugin = <span class="built_in">require</span>(<span class="string">&#x27;terser-webpack-plugin&#x27;</span>)</span><br><span class="line"></span><br><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  optimization: &#123;</span><br><span class="line">    minimizer: [<span class="keyword">new</span> TerserPlugin()],</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


</li>
</ul>
<h3 id="作用域提升"><a href="#作用域提升" class="headerlink" title="作用域提升"></a>作用域提升</h3><ul>
<li><p>代码体积减小</p>
<p>减少调用关系逻辑上的代码，把一些函数进行合并</p>
</li>
<li><p>提高执行效率</p>
<p>要进行引用的话，回花时间进行查找</p>
</li>
<li><p>同样注意 Babel 的 modules 的配置</p>
<p>需要加上 <code>modules: false</code> 的配置</p>
</li>
</ul>
<p>没有启用作用域提升的话，会把这两个模块打成单独的模块，当其中一个依赖到另一个时，会把依赖到的模块 require 进来，再通过 require 进来的模块进行调用</p>
<p>启用作用域提升，会做一个合并和分析，发现有这种依赖调用时，试图把依赖合并到调用里，最终变得更加精简</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**************** util.js ********************/</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="string">&#x27;Hello,Webpack&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**************** index.jsx ******************/</span></span><br><span class="line"><span class="keyword">import</span> str <span class="keyword">from</span> <span class="string">&#x27;./util&#x27;</span>;</span><br><span class="line"><span class="built_in">console</span>.log(str);</span><br><span class="line"></span><br><span class="line"><span class="comment">/***************** 没有 scope hoisting, webpack 打包后 *******************/</span></span><br><span class="line">[</span><br><span class="line">  (<span class="function"><span class="keyword">function</span> (<span class="params"><span class="built_in">module</span>, __webpack_exports__, __webpack_require__</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> __WEBPACK_IMPORTED_MODULE_0__util_js__ = __webpack_require__(<span class="number">1</span>);</span><br><span class="line">    <span class="built_in">console</span>.log(__WEBPACK_IMPORTED_MODULE_0__util_js__[<span class="string">&quot;a&quot;</span>]);</span><br><span class="line">  &#125;),</span><br><span class="line">  (<span class="function"><span class="keyword">function</span> (<span class="params"><span class="built_in">module</span>, __webpack_exports__, __webpack_require__</span>) </span>&#123;</span><br><span class="line">    __webpack_exports__[<span class="string">&quot;a&quot;</span>] = (<span class="string">&#x27;Hello,Webpack&#x27;</span>);</span><br><span class="line">  &#125;)</span><br><span class="line">]</span><br><span class="line"><span class="comment">/************************************/</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/***************** 有 scope hoisting, webpack 打包后 ********************/</span></span><br><span class="line">[</span><br><span class="line">  (<span class="function"><span class="keyword">function</span> (<span class="params"><span class="built_in">module</span>, __webpack_exports__, __webpack_require__</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> util = (<span class="string">&#x27;Hello,Webpack&#x27;</span>);</span><br><span class="line">    <span class="built_in">console</span>.log(util);</span><br><span class="line">  &#125;)</span><br><span class="line">]</span><br><span class="line"><span class="comment">/************************************/</span></span><br></pre></td></tr></table></figure>

<h3 id="Babel-优化配置"><a href="#Babel-优化配置" class="headerlink" title="Babel 优化配置"></a>Babel 优化配置</h3><ul>
<li>在需要的地方引用 polyfill</li>
<li>辅助函数的按需引入</li>
<li>根据目标浏览器按需转换代码</li>
</ul>
<p><strong>按需加载 polyfill</strong></p>
<ul>
<li><p>polyfill 是兼容旧浏览器去进行新功能或新规范的实现</p>
<p>由于这个比较大，需要把所有涉及到的东西都引进来，但我们用到的可能是其中比较小的部分，这时配置 <code>useBuiltIns: &#39;usage&#39;</code> 即可</p>
<p>通过 <code>targets: &#123; browsers: [&#39;&gt;0.25%&#39;] &#125;</code> 来对市场份额超 0.25% 的浏览器进行支持。<a target="_blank" rel="noopener" href="https://github.com/browserslist/browserslist">browserlist</a></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  presets: [</span><br><span class="line">    [</span><br><span class="line">      <span class="string">&#x27;@babel/preset-env&#x27;</span>,</span><br><span class="line">      &#123;</span><br><span class="line">        modules: <span class="literal">false</span>,</span><br><span class="line">        targets: &#123;</span><br><span class="line">          browsers: [<span class="string">&#x27;&gt;0.25%&#x27;</span>],</span><br><span class="line">        &#125;,</span><br><span class="line">        useBuiltIns: <span class="string">&#x27;usage&#x27;</span>,</span><br><span class="line">        bugfixes: <span class="literal">true</span>,</span><br><span class="line">      &#125;,</span><br><span class="line">    ],</span><br><span class="line">    <span class="string">&#x27;@babel/preset-react&#x27;</span>,</span><br><span class="line">  ],</span><br><span class="line">  plugins: [<span class="string">&#x27;@babel/plugin-proposal-class-properties&#x27;</span>, <span class="string">&#x27;@babel/plugin-transform-runtime&#x27;</span>],</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

</li>
</ul>
<p><strong>辅助函数的按需引入</strong></p>
<ul>
<li>声明一个 class，babel 转码后如下图：</li>
</ul>
<p><img data-src="https://gitee.com/lilyn/pic/raw/master/jslearn-img/202203091013592.png"></p>
<h2 id="webpack-依赖优化"><a href="#webpack-依赖优化" class="headerlink" title="webpack 依赖优化"></a>webpack 依赖优化</h2><h3 id="noParse（不解析）"><a href="#noParse（不解析）" class="headerlink" title="noParse（不解析）"></a>noParse（不解析）</h3><ul>
<li><p>提高构建速度</p>
</li>
<li><p>直接通知 webpack 忽略较大的库</p>
<p>通常是第三方的一些类库，一般是比较大的库，且没用模块化的方式去编写，那么它本身也不会有外部的依赖，所以我们就可以不对它进行解析</p>
</li>
<li><p>被忽略的库不能有 import、require、define 的引入方式</p>
</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">module</span>: &#123;</span><br><span class="line">  noParse: <span class="regexp">/lodash/</span>, <span class="comment">// loadsh比较独立</span></span><br><span class="line">  noParse: <span class="regexp">/^(vue|vue-router|vuex|vuex-router-sync)$/</span>, <span class="comment">// vue-cli里的配置</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="DllPlugin"><a href="#DllPlugin" class="headerlink" title="DllPlugin"></a>DllPlugin</h3><ul>
<li><p>避免打包时对不变的库重复构建</p>
<p>比如：react 和 react-dom 其实从开始构建项目开始到最后上线都不太可能变了，我们可以对其进行动态链接库的引用，不再重复构建</p>
</li>
<li><p>提高构建速度</p>
</li>
<li><p>应用场景</p>
<p>生产环境应用的可能性比较小，因为生产环境不会经常打包，慢一点也不会介意</p>
</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* package.json */</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="string">&quot;scripts&quot;</span>: &#123;</span><br><span class="line">    <span class="string">&quot;dll-build&quot;</span>: <span class="string">&quot;cross-env NODE_ENV=production webpack --config webpack.dll.config.js&quot;</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* webpack.dll.config.js */</span></span><br><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">&#x27;path&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> webpack = <span class="built_in">require</span>(<span class="string">&#x27;webpack&#x27;</span>)</span><br><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  mode: <span class="string">&#x27;production&#x27;</span>,</span><br><span class="line">  entry: &#123;</span><br><span class="line">    react: [<span class="string">&#x27;react&#x27;</span>, <span class="string">&#x27;react-dom&#x27;</span>],</span><br><span class="line">  &#125;,</span><br><span class="line">  output: &#123;</span><br><span class="line">    filename: <span class="string">&#x27;[name].dll.js&#x27;</span>,</span><br><span class="line">    path: path.resolve(__dirname, <span class="string">&#x27;dll&#x27;</span>),</span><br><span class="line">    library: <span class="string">&#x27;[name]&#x27;</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">  plugins: [</span><br><span class="line">    <span class="keyword">new</span> webpack.DllPlugin(&#123;</span><br><span class="line">      name: <span class="string">&#x27;[name]&#x27;</span>,</span><br><span class="line">      path: path.resolve(__dirname, <span class="string">&#x27;dll/[name].manifest.json&#x27;</span>),</span><br><span class="line">    &#125;),</span><br><span class="line">  ],</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* webpack.config.js */</span></span><br><span class="line"><span class="keyword">const</span> DllReferencePlugin = <span class="built_in">require</span>(<span class="string">&#x27;webpack/lib/DllReferencePlugin&#x27;</span>);</span><br><span class="line"><span class="built_in">module</span>.exports = smp.wrap(&#123;</span><br><span class="line">  plugins: [</span><br><span class="line">    <span class="comment">/* 动态链接库引用 */</span></span><br><span class="line">    <span class="keyword">new</span> DllReferencePlugin(&#123;</span><br><span class="line">      manifest: <span class="built_in">require</span>(<span class="string">`<span class="subst">$&#123;__dirname&#125;</span>/dll/react.manifest.json`</span>),</span><br><span class="line">    &#125;),</span><br><span class="line">  ],</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="webpack-细节优化"><a href="#webpack-细节优化" class="headerlink" title="webpack 细节优化"></a>webpack 细节优化</h2><h3 id="代码拆分"><a href="#代码拆分" class="headerlink" title="代码拆分"></a>代码拆分</h3><ul>
<li>把单个 bundle文件拆分成若干个 bundles/chunks</li>
<li>缩短首屏加载时间</li>
</ul>
<p><strong>webpack 代码拆分方法：</strong></p>
<ul>
<li><p>手工定义入口</p>
</li>
<li><p>splitChunks 提取公有代码，拆分业务代码与第三方库</p>
<ol>
<li>把我们代码中重复使用的东西提取出来</li>
<li>把我们这个业务逻辑与第三方依赖进行拆分</li>
</ol>
<p>webpack 处理文件路径时，它们始终包含 Unix 系统中的 <code>/</code> 和 Windows 系统中的 <code>\</code>，所以会在前面加上 <code>[\\/]</code></p>
<p>chunks：有效值为 <code>all</code>、<code>async</code>、<code>initial</code>，<code>initial</code> 是同步加载，<code>async</code> 是一部加载</p>
<p>minChunks：拆分前必须共享模块的最小 chunks 数</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">module</span>.exports = smp.wrap(&#123;</span><br><span class="line">  optimization: &#123;</span><br><span class="line">    splitChunks: &#123;</span><br><span class="line">      cacheGroups: &#123;</span><br><span class="line">        vendor: &#123;</span><br><span class="line">          name: <span class="string">&#x27;vendor&#x27;</span>,</span><br><span class="line">          test: <span class="regexp">/[\\/]node_modules[\\/]/</span>,</span><br><span class="line">          minSize: <span class="number">0</span>,</span><br><span class="line">          minChunks: <span class="number">1</span>,</span><br><span class="line">          priority: <span class="number">10</span>,</span><br><span class="line">          chunks: <span class="string">&#x27;initial&#x27;</span>,</span><br><span class="line">        &#125;,</span><br><span class="line">        common: &#123;</span><br><span class="line">          name: <span class="string">&#x27;common&#x27;</span>,</span><br><span class="line">          test: <span class="regexp">/[\\/]src[\\/]/</span>,</span><br><span class="line">          chunks: <span class="string">&#x27;all&#x27;</span>,</span><br><span class="line">          minSize: <span class="number">0</span>,</span><br><span class="line">          minChunks: <span class="number">2</span>,</span><br><span class="line">        &#125;,</span><br><span class="line">      &#125;,</span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>
</li>
<li><p>动态加载</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">&lt;Suspense fallback=&#123;&lt;div&gt;Loading...&lt;/div&gt;&#125;&gt;</span><br><span class="line">  &lt;Card</span><br><span class="line">    key=&#123;panel.name&#125;</span><br><span class="line">    image=&#123;panel.image&#125;</span><br><span class="line">    title=&#123;panel.name&#125;</span><br><span class="line">    route=&#123;panel.route&#125;</span><br><span class="line">    description=&#123;panel.body&#125;</span><br><span class="line">  /&gt;</span><br><span class="line"><span class="tag">&lt;/<span class="name">Suspense</span>&gt;</span></span><br></pre></td></tr></table></figure>

</li>
</ul>
<h3 id="资源压缩"><a href="#资源压缩" class="headerlink" title="资源压缩"></a>资源压缩</h3><ul>
<li>Terser 压缩 JS</li>
<li>mini-css-extract-plugin 压缩 CSS</li>
<li>HtmlWebpackPlugin-minify 压缩 HTML</li>
</ul>
<blockquote>
<p><a target="_blank" rel="noopener" href="https://v4.webpack.docschina.org/concepts/mode/">webpack4 mode</a></p>
</blockquote>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// webpack.production.config.js</span></span><br><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  mode: <span class="string">&#x27;production&#x27;</span>,</span><br><span class="line">  performance: &#123;</span><br><span class="line">    hints: <span class="string">&#x27;warning&#x27;</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">  output: &#123;</span><br><span class="line">    pathinfo: <span class="literal">false</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">  optimization: &#123;</span><br><span class="line">    namedModules: <span class="literal">false</span>,</span><br><span class="line">    namedChunks: <span class="literal">false</span>,</span><br><span class="line">    nodeEnv: <span class="string">&#x27;production&#x27;</span>,</span><br><span class="line">    flagIncludedChunks: <span class="literal">true</span>,</span><br><span class="line">    occurrenceOrder: <span class="literal">true</span>,</span><br><span class="line">    sideEffects: <span class="literal">true</span>,</span><br><span class="line">    usedExports: <span class="literal">true</span>,</span><br><span class="line">    concatenateModules: <span class="literal">true</span>,</span><br><span class="line">    splitChunks: &#123;</span><br><span class="line">      hidePathInfo: <span class="literal">true</span>,</span><br><span class="line">      minSize: <span class="number">30000</span>,</span><br><span class="line">      maxAsyncRequests: <span class="number">5</span>,</span><br><span class="line">      maxInitialRequests: <span class="number">3</span>,</span><br><span class="line">    &#125;,</span><br><span class="line">    noEmitOnErrors: <span class="literal">true</span>,</span><br><span class="line">    checkWasmTypes: <span class="literal">true</span>,</span><br><span class="line">    minimize: <span class="literal">true</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">  plugins: [</span><br><span class="line">    <span class="keyword">new</span> TerserPlugin(<span class="comment">/* ... */</span>),</span><br><span class="line">    <span class="keyword">new</span> webpack.DefinePlugin(&#123; <span class="string">&#x27;process.env.NODE_ENV&#x27;</span>: <span class="built_in">JSON</span>.stringify(<span class="string">&#x27;production&#x27;</span>) &#125;),</span><br><span class="line">    <span class="keyword">new</span> webpack.optimize.ModuleConcatenationPlugin(),</span><br><span class="line">    <span class="keyword">new</span> webpack.NoEmitOnErrorsPlugin(),</span><br><span class="line">  ],</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>mini-css-extract-plugin 压缩 CSS</strong></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  plugins: [</span><br><span class="line">    <span class="keyword">new</span> MiniCssExtractPlugin(&#123;</span><br><span class="line">      filename: <span class="string">&#x27;[name].[hash].css&#x27;</span>,</span><br><span class="line">      chunkFilename: <span class="string">&#x27;[id].[chunkhash:8].css&#x27;</span>,</span><br><span class="line">    &#125;),</span><br><span class="line">    <span class="keyword">new</span> OptimizeCssAssetsPlugin(&#123;</span><br><span class="line">      cssProcessorPluginOptions: &#123;</span><br><span class="line">        preset: [<span class="string">&#x27;default&#x27;</span>, &#123; <span class="attr">discardComments</span>: &#123; <span class="attr">removeAll</span>: <span class="literal">true</span> &#125; &#125;],</span><br><span class="line">      &#125;,</span><br><span class="line">      canPrint: <span class="literal">true</span>,</span><br><span class="line">    &#125;),</span><br><span class="line">  ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>HtmlWebpackPlugin-minify 压缩 HTML</strong></p>
<blockquote>
<p><a target="_blank" rel="noopener" href="https://github.com/jantimon/html-webpack-plugin#minification">minification</a></p>
</blockquote>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  collapseWhitespace: <span class="literal">true</span>, <span class="comment">// 移除空格、换行符</span></span><br><span class="line">  keepClosingSlash: <span class="literal">true</span>, <span class="comment">// 保留元素的末尾斜杠</span></span><br><span class="line">  removeComments: <span class="literal">true</span>, <span class="comment">// 移除注释</span></span><br><span class="line">  removeRedundantAttributes: <span class="literal">true</span>, <span class="comment">// 移除冗余属性（默认值）</span></span><br><span class="line">  removeScriptTypeAttributes: <span class="literal">true</span>, <span class="comment">// 移除script标签中的type属性</span></span><br><span class="line">  removeStyleLinkTypeAttributes: <span class="literal">true</span>, <span class="comment">// 移除style标签中的type属性</span></span><br><span class="line">  useShortDoctype: <span class="literal">true</span> <span class="comment">// 使用html5短的描述方式</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="资源持久化缓存"><a href="#资源持久化缓存" class="headerlink" title="资源持久化缓存"></a>资源持久化缓存</h3><ul>
<li><p>每次打包的资源文件有唯一的 hash 值</p>
</li>
<li><p>修改后只有受影响到的文件 hash 变化</p>
</li>
<li><p>充分利用浏览器缓存</p>
<p>hash 特点：离散唯一的值，如果内容不变，计算出来的值也不变</p>
<p>contenthash 会根据内容生成 hash，当只改 JS 时，进行重新打包后，CSS 就会保持原有的 hash 值。当更新部署时，就可以充分利用浏览器缓存，这样就可以保证用户体验且能进行一个平稳的更新过度</p>
</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  output: &#123;</span><br><span class="line">    path: <span class="string">`<span class="subst">$&#123;__dirname&#125;</span>/build`</span>,</span><br><span class="line">    filename: <span class="string">&#x27;[name].[hash].bundle.js&#x27;</span>,</span><br><span class="line">    chunkFilename: <span class="string">&#x27;[name].[chunkhash:8].bundle.js&#x27;</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">  plugins: [</span><br><span class="line">    <span class="keyword">new</span> MiniCssExtractPlugin(&#123;</span><br><span class="line">      filename: <span class="string">&#x27;[name].[contenthash].css&#x27;</span>,</span><br><span class="line">      chunkFilename: <span class="string">&#x27;[id].[contenthash:8].css&#x27;</span>,</span><br><span class="line">    &#125;),</span><br><span class="line">  ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="应用大小检测与分析"><a href="#应用大小检测与分析" class="headerlink" title="应用大小检测与分析"></a>应用大小检测与分析</h3><ul>
<li>Stats 分析与可视化图</li>
<li>webpack-bundle-analyzer 进行体积分析</li>
<li>speed-measure-webpack-plugin 速度分析</li>
</ul>
<blockquote>
<p><a target="_blank" rel="noopener" href="https://alexkuz.github.io/webpack-chart/">webpack-chart</a></p>
</blockquote>
<p>通过：<code>webpack --profile --json &gt; stats.json</code> 生成 <code>stats.json</code>文件，之后将这个上传到这个网站即可</p>
<p><img data-src="https://gitee.com/lilyn/pic/raw/master/jslearn-img/202203101448357.png"></p>
<p>这个可能还是不够细，想进一步分析可以使用 bundle-analyzer 工具实现，这里使用 <code>source-map-explorer</code> 进一步分析</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm i source-map-explorer</span><br></pre></td></tr></table></figure>

<p>这个分析不是基于我们的 bundle 文件，而是基于 sourcemap，需要需要生成 sourcemap</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* package.json */</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="string">&quot;scripts&quot;</span>: &#123;</span><br><span class="line">    <span class="string">&quot;analyze&quot;</span>: <span class="string">&quot;source-map-explorer &#x27;build/*.js&#x27;&quot;</span></span><br><span class="line">  &#125;,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* webpack.config.js */</span></span><br><span class="line"><span class="built_in">module</span>.exports = smp.wrap(&#123;</span><br><span class="line">  mode: <span class="string">&#x27;production&#x27;</span>,</span><br><span class="line">  devtool: <span class="string">&#x27;source-map&#x27;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><img data-src="https://gitee.com/lilyn/pic/raw/master/jslearn-img/202203101457701.png"></p>
<p>官方推荐的 <code>bundle-analyzer</code> 可以得到可视化图，不过相比 source-map-explorer 相比，它只能看个大概，少一些具体内容</p>
<p><img data-src="https://gitee.com/lilyn/pic/raw/master/jslearn-img/202203101459723.png"></p>
<p>速度分析可以使用<code>speed-measure-webpack-plugin</code>，运行 <code>npm run build</code> 即可看到所有 plugins 和所有 loaders 的使用情况</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> SpeedMeasurePlugin = <span class="built_in">require</span>(<span class="string">&#x27;speed-measure-webpack-plugin&#x27;</span>)</span><br><span class="line"><span class="keyword">const</span> smp = <span class="keyword">new</span> SpeedMeasurePlugin()</span><br><span class="line"></span><br><span class="line"><span class="built_in">module</span>.exports = smp.wrap(&#123;...&#125;)</span><br></pre></td></tr></table></figure>

<h2 id="React-按需加载实现方式"><a href="#React-按需加载实现方式" class="headerlink" title="React 按需加载实现方式"></a>React 按需加载实现方式</h2><ul>
<li>React router 基于 webpack 动态引入</li>
<li>使用 Reloadable 高级组件</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> loadable <span class="keyword">from</span> <span class="string">&#x27;@loadable/component&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用React-Loadable动态加载组件</span></span><br><span class="line"><span class="keyword">const</span> LoadableAbout = loadable(<span class="function">() =&gt;</span> <span class="keyword">import</span>(<span class="string">&#x27;./About.jsx&#x27;</span>), &#123;</span><br><span class="line">  fallback: <span class="string">&#x27;&lt;div&gt;loading...&lt;/div&gt;&#x27;</span>,</span><br><span class="line">&#125;)</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">App</span> <span class="keyword">extends</span> <span class="title">React</span>.<span class="title">Component</span> </span>&#123;</span><br><span class="line">  <span class="function"><span class="title">render</span>(<span class="params"></span>)</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> (</span><br><span class="line">      &lt;Router&gt;</span><br><span class="line">        &lt;Switch&gt;</span><br><span class="line">          &lt;Route exact path=<span class="string">&quot;/&quot;</span> component=&#123;Home&#125; /&gt;</span><br><span class="line">          &lt;Route path=<span class="string">&quot;/about&quot;</span> component=&#123;LoadableAbout&#125; /&gt;</span><br><span class="line">        &lt;/Switch&gt;</span><br><span class="line">      &lt;/Router&gt;</span><br><span class="line">    )</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>代码拆分最初是为了解决一个过大请求的问题</p>
<ul>
<li><p>通过一个请求，把整个包加载到首页，这时网络开销相对少但是包体积大，所以下载耗时长</p>
</li>
<li><p>我们可以把较大的包做拆解，拆分成若干个小包，小包只有被调用时才会加载（按需加载）</p>
<p>假如拆分水平定义到组件，那所有组件都被拆分成一个独立的模块，就会有很多 bundle 或 chunk，那就要发起若干个请求，开销会更大</p>
</li>
<li><p>通常最合理的方式就是按照路由进行按需加载，而当页面上一些组件在不同路由页面会被进行复用时，才把组件单独进行拆解</p>
</li>
</ul>

    </div>

    
    
    

	<div>
		  
			
<div class="my_post_copyright clearfix">
  <script src="//cdn.bootcss.com/clipboard.js/1.5.10/clipboard.min.js"></script>
  
  <!-- JS库 sweetalert 可修改路径 -->
  <script src="https://cdn.bootcss.com/jquery/2.0.0/jquery.min.js"></script>
  <script src="https://unpkg.com/sweetalert/dist/sweetalert.min.js"></script>
  <article class="box-left">
    <img src="https://gitee.com/lilyn/pic/raw/master/logo.jpg">
  </article>
  <article class="box-right">
    <p><span>本文标题:</span><a href="/posts/e8da84b8/">优化5.构建优化</a></p>
    <p><span>文章作者:</span><a href="/" title="访问 LiLyn 的个人博客">LiLyn</a></p>
    <p><span>原始链接:</span><a href="/posts/e8da84b8/" title="优化5.构建优化">http://llmysnow.top/posts/e8da84b8/</a>
    <span class="copy-path"  title="点击复制文章链接"><i class="fa fa-clipboard" data-clipboard-text="http://llmysnow.top/posts/e8da84b8/"  aria-label="复制成功！"></i></span>
  </p>
    <p><span>许可协议:</span>转载请保留原文链接及作者。</p>  
  </article>
</div>
<script> 
    var clipboard = new Clipboard('.fa-clipboard');
    $(".fa-clipboard").click(function(){
      clipboard.on('success', function(){
        swal({   
          title: "",   
          text: '复制成功',
          icon: "success", 
          showConfirmButton: true
          });
    });
    });  
</script>

		  
	</div>

      <footer class="post-footer">
          <div class="post-tags">
              <a href="/tags/%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96/" rel="tag"><i class="fa fa-tag"></i> 性能优化</a>
              <a href="/tags/webpack-%E4%BC%98%E5%8C%96%E9%85%8D%E7%BD%AE/" rel="tag"><i class="fa fa-tag"></i> webpack 优化配置</a>
              <a href="/tags/webpack-%E4%BE%9D%E8%B5%96%E4%BC%98%E5%8C%96/" rel="tag"><i class="fa fa-tag"></i> webpack 依赖优化</a>
              <a href="/tags/webpack-%E7%BB%86%E8%8A%82%E4%BC%98%E5%8C%96/" rel="tag"><i class="fa fa-tag"></i> webpack 细节优化</a>
          </div>
		 
		<!--post-tags 彩色标签-->
		<script type="text/javascript">
		var tagsall=document.getElementsByClassName("post-tags")
		for (var i = tagsall.length - 1; i >= 0; i--){
			var tags=tagsall[i].getElementsByTagName("a");
			for (var j = tags.length - 1; j >= 0; j--) {
				var r=Math.floor(Math.random()*75+130);
				var g=Math.floor(Math.random()*75+100);
				var b=Math.floor(Math.random()*75+80);
				tags[j].style.background = "rgb("+r+","+g+","+b+")";
				tags[j].style.color = "#fff";
				tags[j].style.padding = "0 10px";
			}
		}                        
		</script>

        


        
    <div class="post-nav">
      <div class="post-nav-item">
    <a href="/posts/a7b3e4ca/" rel="prev" title="优化4.资源优化">
      <i class="fa fa-chevron-left"></i> 优化4.资源优化
    </a></div>
      <div class="post-nav-item">
    <a href="/posts/66264067/" rel="next" title="优化6.传输加载优化">
      优化6.传输加载优化 <i class="fa fa-chevron-right"></i>
    </a></div>
    </div>
      </footer>
    
  </article>
  
  
  



          </div>
          

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
          <div class="post-toc motion-element"><ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#webpack-%E4%BC%98%E5%8C%96%E9%85%8D%E7%BD%AE"><span class="nav-text">webpack 优化配置</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#Tree-shaking"><span class="nav-text">Tree-shaking</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#JS-%E5%8E%8B%E7%BC%A9"><span class="nav-text">JS 压缩</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E4%BD%9C%E7%94%A8%E5%9F%9F%E6%8F%90%E5%8D%87"><span class="nav-text">作用域提升</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#Babel-%E4%BC%98%E5%8C%96%E9%85%8D%E7%BD%AE"><span class="nav-text">Babel 优化配置</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#webpack-%E4%BE%9D%E8%B5%96%E4%BC%98%E5%8C%96"><span class="nav-text">webpack 依赖优化</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#noParse%EF%BC%88%E4%B8%8D%E8%A7%A3%E6%9E%90%EF%BC%89"><span class="nav-text">noParse（不解析）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#DllPlugin"><span class="nav-text">DllPlugin</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#webpack-%E7%BB%86%E8%8A%82%E4%BC%98%E5%8C%96"><span class="nav-text">webpack 细节优化</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E4%BB%A3%E7%A0%81%E6%8B%86%E5%88%86"><span class="nav-text">代码拆分</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E8%B5%84%E6%BA%90%E5%8E%8B%E7%BC%A9"><span class="nav-text">资源压缩</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E8%B5%84%E6%BA%90%E6%8C%81%E4%B9%85%E5%8C%96%E7%BC%93%E5%AD%98"><span class="nav-text">资源持久化缓存</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%BA%94%E7%94%A8%E5%A4%A7%E5%B0%8F%E6%A3%80%E6%B5%8B%E4%B8%8E%E5%88%86%E6%9E%90"><span class="nav-text">应用大小检测与分析</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#React-%E6%8C%89%E9%9C%80%E5%8A%A0%E8%BD%BD%E5%AE%9E%E7%8E%B0%E6%96%B9%E5%BC%8F"><span class="nav-text">React 按需加载实现方式</span></a></li></ol></div>
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="LiLyn"
      src="/images/logo.jpg">
  <p class="site-author-name" itemprop="name">LiLyn</p>
  <div class="site-description" itemprop="description"></div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/archives/">
        
          <span class="site-state-item-count">70</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
            <a href="/categories/">
          
        <span class="site-state-item-count">10</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/tags/">
          
        <span class="site-state-item-count">162</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>
  <div class="links-of-author motion-element">
      <span class="links-of-author-item">
        <a href="https://github.com/llwodexue" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;llwodexue" rel="noopener" target="_blank"><i class="fab fa-github fa-fw"></i>GitHub</a>
      </span>
      <span class="links-of-author-item">
        <a href="https://blog.csdn.net/qq_38689395" title="CSDN → https:&#x2F;&#x2F;blog.csdn.net&#x2F;qq_38689395" rel="noopener" target="_blank"><i class="fas fa-copyright fa-fw"></i>CSDN</a>
      </span>
  </div>


  <div class="links-of-blogroll motion-element">
    <div class="links-of-blogroll-title"><i class="fa fa-link fa-fw"></i>
      友情链接
    </div>
    <ul class="links-of-blogroll-list">
        <li class="links-of-blogroll-item">
          <a href="https://scx69.gitee.io/blogs/" title="https:&#x2F;&#x2F;scx69.gitee.io&#x2F;blogs&#x2F;" rel="noopener" target="_blank">花开满城</a>
        </li>
        <li class="links-of-blogroll-item">
          <a href="http://yixin-oss.gitee.io/daytoy/" title="http:&#x2F;&#x2F;yixin-oss.gitee.io&#x2F;daytoy&#x2F;" rel="noopener" target="_blank">daytoy</a>
        </li>
    </ul>
  </div>

      </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

        

<div class="copyright">
  
  &copy; 
  <span itemprop="copyrightYear">2022</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">LiLyn</span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item-icon">
      <i class="fa fa-chart-area"></i>
    </span>
    <span title="站点总字数">463k</span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item-icon">
      <i class="fa fa-coffee"></i>
    </span>
    <span title="站点阅读时长">7:01</span>
</div>

<!--
  <div class="powered-by">由 <a href="https://hexo.io/" class="theme-link" rel="noopener" target="_blank">Hexo</a> & <a href="https://theme-next.org/" class="theme-link" rel="noopener" target="_blank">NexT.Gemini</a> 强力驱动
  </div>-->

<!--
<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
<div class="powered-by">
  <i class="fa fa-user-md"></i>
  <span id="busuanzi_container_site_pv">
    本站访问量:<span id="busuanzi_value_site_pv"></span>次
  </span>
  <span class="post-meta-divider">|</span>
  <span id="busuanzi_container_site_uv">
    本站总访客量：<span id="busuanzi_value_site_uv"></span>人
  </span>
</div>-->

        








      </div>
    </footer>
  </div>

  
  <script src="/lib/anime.min.js"></script>
  <script src="//cdn.jsdelivr.net/npm/lozad@1/dist/lozad.min.js"></script>
  <script src="/lib/velocity/velocity.min.js"></script>
  <script src="/lib/velocity/velocity.ui.min.js"></script>

<script src="/js/utils.js"></script>

<script src="/js/motion.js"></script>


<script src="/js/schemes/pisces.js"></script>


<script src="/js/next-boot.js"></script>




  
  <script>
    (function(){
      var canonicalURL, curProtocol;
      //Get the <link> tag
      var x=document.getElementsByTagName("link");
		//Find the last canonical URL
		if(x.length > 0){
			for (i=0;i<x.length;i++){
				if(x[i].rel.toLowerCase() == 'canonical' && x[i].href){
					canonicalURL=x[i].href;
				}
			}
		}
    //Get protocol
	    if (!canonicalURL){
	    	curProtocol = window.location.protocol.split(':')[0];
	    }
	    else{
	    	curProtocol = canonicalURL.split(':')[0];
	    }
      //Get current URL if the canonical URL does not exist
	    if (!canonicalURL) canonicalURL = window.location.href;
	    //Assign script content. Replace current URL with the canonical URL
      !function(){var e=/([http|https]:\/\/[a-zA-Z0-9\_\.]+\.baidu\.com)/gi,r=canonicalURL,t=document.referrer;if(!e.test(r)){var n=(String(curProtocol).toLowerCase() === 'https')?"https://sp0.baidu.com/9_Q4simg2RQJ8t7jm9iCKT-xh_/s.gif":"//api.share.baidu.com/s.gif";t?(n+="?r="+encodeURIComponent(document.referrer),r&&(n+="&l="+r)):r&&(n+="?l="+r);var i=new Image;i.src=n}}(window);})();
  </script>




  
<script src="/js/local-search.js"></script>













  

  

  <!-- 动态线条背景 -->
  <script type="text/javascript" src="//cdn.bootcss.com/canvas-nest.js/1.0.0/canvas-nest.min.js"></script>
  <!-- 页面点击小红心 -->
  <script type="text/javascript">
	!function(e,t,a){function n(){c(".heart{width: 10px;height: 10px;position: fixed;background: #f00;transform: rotate(45deg);-webkit-transform: rotate(45deg);-moz-transform: rotate(45deg);}.heart:after,.heart:before{content: '';width: inherit;height: inherit;background: inherit;border-radius: 50%;-webkit-border-radius: 50%;-moz-border-radius: 50%;position: fixed;}.heart:after{top: -5px;}.heart:before{left: -5px;}"),o(),r()}function r(){for(var e=0;e<d.length;e++)d[e].alpha<=0?(t.body.removeChild(d[e].el),d.splice(e,1)):(d[e].y--,d[e].scale+=.004,d[e].alpha-=.013,d[e].el.style.cssText="left:"+d[e].x+"px;top:"+d[e].y+"px;opacity:"+d[e].alpha+";transform:scale("+d[e].scale+","+d[e].scale+") rotate(45deg);background:"+d[e].color+";z-index:99999");requestAnimationFrame(r)}function o(){var t="function"==typeof e.onclick&&e.onclick;e.onclick=function(e){t&&t(),i(e)}}function i(e){var a=t.createElement("div");a.className="heart",d.push({el:a,x:e.clientX-5,y:e.clientY-5,scale:1,alpha:1,color:s()}),t.body.appendChild(a)}function c(e){var a=t.createElement("style");a.type="text/css";try{a.appendChild(t.createTextNode(e))}catch(t){a.styleSheet.cssText=e}t.getElementsByTagName("head")[0].appendChild(a)}function s(){return"rgb("+~~(255*Math.random())+","+~~(255*Math.random())+","+~~(255*Math.random())+")"}var d=[];e.requestAnimationFrame=function(){return e.requestAnimationFrame||e.webkitRequestAnimationFrame||e.mozRequestAnimationFrame||e.oRequestAnimationFrame||e.msRequestAnimationFrame||function(e){setTimeout(e,1e3/60)}}(),n()}(window,document);
  </script>
<script src="/live2dw/lib/L2Dwidget.min.js?094cbace49a39548bed64abff5988b05"></script><script>L2Dwidget.init({"pluginRootPath":"live2dw/","pluginJsPath":"lib/","pluginModelPath":"assets/","tagMode":false,"log":false,"model":{"jsonPath":"/live2dw/assets/hijiki.model.json"},"display":{"position":"right","width":150,"height":300},"mobile":{"show":true},"react":{"opacity":0.7}});</script></body>
</html>